package com.yanqu.road.server.manager.cricketcourt;

import com.yanqu.road.entity.cricket.CricketSystemConfig;
import com.yanqu.road.entity.cricket.config.CricketCourtConfig;
import com.yanqu.road.entity.cricket.court.*;
import com.yanqu.road.entity.cricket.court.helper.CourtGroupNumHelper;
import com.yanqu.road.entity.cricket.court.helper.CricketCourtRankRewardHelper;
import com.yanqu.road.entity.cricket.court.log.LogCricketCourtChangeScore;
import com.yanqu.road.entity.cricket.court.log.LogCricketCourtRoundRank;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.entity.servercenter.group.CricketServerGroup;
import com.yanqu.road.logic.bussiness.config.CricketConfigBusiness;
import com.yanqu.road.logic.bussiness.cricket.CrossCricketBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.model.cricket.CricketUserBaseInfo;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.cricket.CricketProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.cricket.CricketDbData;
import com.yanqu.road.server.manager.cricket.entity.DbCricketHotBattleLog;
import com.yanqu.road.server.manager.cricket.entity.business.CricketCrossBusiness;
import com.yanqu.road.server.manager.cricketcourt.log.CrossCricketCourtLog;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.manger.CricketServerGroupMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.pb.CrossCricketPb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.UUIDHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 蛐蛐竞技场
 */
public class CrossCricketCourtMgr extends TempMgr {

    private static RandomHelper randomHelper = new RandomHelper();

    /**
     * 当前竞技场信息
     */
    private static Map<Integer, CricketCourtData> courtDataMap = new ConcurrentHashMap<>();

    private static CricketSystemConfig config;

    /**
     * 分组id同一轮次递增且唯一，不区分赛场
     * 竞技场分组信息=> 赛场,分组,分组信息
     */
    private static Map<Integer, Map<Integer, CricketCourtGroupData>> courtGroupDataMap = new ConcurrentHashMap<>();

    /**
     * serverId,userId,竞技场玩家信息
     */
    private static Map<Long, Map<Long, CricketCourtUserData>> courtUserDataMap = new ConcurrentHashMap<>();

    /**
     * 榜单信息=> 轮次,赛场,分组,榜单
     */
    private static Map<Integer, Map<Integer, Map<Integer, CricketCourtRankListModel>>> rankListModelMap = new ConcurrentHashMap<>();

    /**
     * 宗师榜
     * 分组匹配id，宗师榜
     */
    private static Map<Integer, LinkedList<CricketCourtTopUserData>> topRankListMap = new ConcurrentHashMap<>();

    private static CricketDbData cricketDbData = new CricketDbData();

    /**
     * 轮次切换中，不允许操作
     */
    private static boolean inRoundChange = false;

    /**
     * 榜单最大长度,暂不限制，在分组里都是上榜的，由分组名单控制
     */
    public static int getMaxRank() {
        return 99999;
    }

    /**
     * 分组id
     */
    private static AtomicInteger maxGroupId = new AtomicInteger(0);


    /**
     * 上一轮匹配分组
     * 匹配分组id，匹配分组
     */
    private static Map<Integer, CricketCourtGroupMatchData> lastGroupMatchDataMap = new ConcurrentHashMap<>();

    /**
     * 匹配分组
     * 匹配分组id，匹配分组
     */
    private static Map<Integer, CricketCourtGroupMatchData> groupMatchDataMap = new ConcurrentHashMap<>();

    /**
     * 匹配分组id
     */
    private static AtomicInteger maxMatchGroupId = new AtomicInteger(0);

    /**
     * 当前竞技场轮次
     */
    private static AtomicInteger curRound = new AtomicInteger(0);

    private static Object lock = new Object();

    private static int channelId;

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        try {
            config = new CricketSystemConfig();
            config.setCricketCourtConfigMap(CricketConfigBusiness.getCricketCourtConfig(ConfigHelper.getInt("channelId")));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        channelId = ConfigHelper.getInt("channelId");
        // 系统没开放不需加载数据
        if (!CrossCricketCourtMgr.channelSystemOpen()) {
            return true;
        }
        // 加载数据
        courtDataMap = CrossCricketBussiness.getCricketCourtDataMap();
        int tempMaxRound = 0;
        for (CricketCourtData courtData : courtDataMap.values()) {
            tempMaxRound = Math.max(tempMaxRound, courtData.getRound());
        }
        // 记录下最大轮次,也就是当前轮次
        curRound = new AtomicInteger(tempMaxRound);
        boolean initCourt = false;
        if (curRound.get() == 0) {
            CricketCourtData courtData = new CricketCourtData();
            // 初始化第一轮
            courtData.setRound(curRound.incrementAndGet());
            // 结算时间
            courtData.setRewardTime(DateHelper.getTodayZeroTimeStamp() + GameConfig.CRICKET_FIGHT_SETTLE_TIME * DateHelper.MINUTE_MILLIONS);
            // 结束时间
            courtData.setEndTime(DateHelper.getTodayZeroTimeStamp() + GameConfig.CRICKET_FIGHT_LOOP_DAY * DateHelper.DAY_MILLIONS);
            courtData.setGenerateGroup(false);
            courtData.setRankReward(false);
            courtData.setUpdateTime(System.currentTimeMillis());
            courtData.setInsertOption();
            courtDataMap.put(curRound.get(), courtData);
            initCourt = true;
        }
        Set<Integer> allCourtIdSet = config.getCricketCourtConfigMap().keySet();
        courtUserDataMap = CrossCricketBussiness.getCricketCourtUserDataMap();
        for (Map<Long, CricketCourtUserData> userDataMap : courtUserDataMap.values()) {
            for (CricketCourtUserData userData : userDataMap.values()) {
                if (!allCourtIdSet.contains(userData.getCourtId())) {
                    userData.setCourtId(-1);
                    userData.setGroupId(-1);
                }
            }
        }
        // 处理下脏数据
        courtGroupDataMap = CrossCricketBussiness.getCricketCourtGroupDataMap(curRound.get());
        lockGroupMap = CrossCricketBussiness.getCricketCourtLockGroupMap(curRound.get());
        if (lockGroupMap.isEmpty()) {
            // 锁定一下
            lockMatchGroup();
        }

        // 最大的分组编号
        int maxGid = 0;
        for (Map<Integer, CricketCourtGroupData> dataMap : courtGroupDataMap.values()) {
            for (CricketCourtGroupData groupData : dataMap.values()) {
                maxGid = Math.max(maxGid, groupData.getGroupId());
            }
        }
        maxGroupId = new AtomicInteger(maxGid);


        // 获取上轮的匹配分组
        lastGroupMatchDataMap = CrossCricketBussiness.getCricketCourtGroupMatchDataMap(curRound.get() - 1);

        // 获取本轮的匹配分组
        groupMatchDataMap = CrossCricketBussiness.getCricketCourtGroupMatchDataMap(curRound.get());

        if (groupMatchDataMap.isEmpty()) {
            // 本轮分组为空,生成本轮分组
            generateGroup();
        }

        // 最大的匹配分组编号
        int maxMatchGid = 0;
        for (CricketCourtGroupMatchData groupMatchData : groupMatchDataMap.values()) {
            maxMatchGid = Math.max(maxMatchGid, groupMatchData.getMatchGroupId());
        }
        maxMatchGroupId = new AtomicInteger(maxMatchGid);

        // 初始化下榜单分组
        initAllRankList();

        // 热门战报
        Map<Long, DbCricketHotBattleLog> dbCricketHotBattleLogMap = CricketCrossBusiness.getDbCricketHotBattleLogMap(battleLogLimit());
        for (DbCricketHotBattleLog dbCricketHotBattleLog : dbCricketHotBattleLogMap.values()) {
            cricketDbData.addDbCricketHotBattleLog(dbCricketHotBattleLog);
            if (dbCricketHotBattleLog.getBattleLogId() > cricketDbData.getBattleLogIdAutoIncrease().get()) {
                cricketDbData.getBattleLogIdAutoIncrease().set(dbCricketHotBattleLog.getBattleLogId());
            }
        }

        // 加载宗师榜
        int lastRound = curRound.get() - 1;
        if (lastRound > 0) {
            topRankListMap = CrossCricketBussiness.getCricketCourtTopUserList(lastRound);
            // 根据排名排个序
            for (LinkedList<CricketCourtTopUserData> list : topRankListMap.values()) {
                list.sort(Comparator.comparingInt(CricketCourtTopUserData::getRank));
            }
        }

        // 初始化一下分组
        if (initCourt) {
            generateGroup();
        }
        return true;
    }

    private static void initAllRankList() {
        for (Map<Integer, CricketCourtGroupData> dataMap : courtGroupDataMap.values()) {
            for (CricketCourtGroupData groupData : dataMap.values()) {
                getRankListModel(groupData.getRound(), groupData.getCourtId(), groupData.getGroupId());
            }
        }
    }

    @Override
    public boolean stop() {
        return true;
    }


    @Override
    public boolean save() {
        for (CricketCourtData courtData : courtDataMap.values()) {
            if (courtData.isInsertOption()) {
                CrossCricketBussiness.addCricketCourtData(courtData);
            } else if (courtData.isUpdateOption()) {
                CrossCricketBussiness.updateCricketCourtData(courtData);
            }
        }
        for (Map<Long, CricketCourtUserData> dataMap : courtUserDataMap.values()) {
            for (CricketCourtUserData userData : dataMap.values()) {
                if (userData.isInsertOption()) {
                    CrossCricketBussiness.addCricketCourtUserData(userData);
                } else if (userData.isUpdateOption()) {
                    CrossCricketBussiness.updateCricketCourtUserData(userData);
                }
            }
        }
        for (Map<Integer, CricketCourtGroupData> dataMap : courtGroupDataMap.values()) {
            for (CricketCourtGroupData groupData : dataMap.values()) {
                if (groupData.isInsertOption()) {
                    CrossCricketBussiness.addCricketCourtGroupData(groupData);
                } else if (groupData.isUpdateOption()) {
                    CrossCricketBussiness.updateCricketCourtGroupData(groupData);
                }
            }
        }

        for (CricketCourtGroupMatchData matchData : groupMatchDataMap.values()) {
            if (matchData.isInsertOption()) {
                CrossCricketBussiness.addCricketCourtGroupMatchData(matchData);
            } else if (matchData.isUpdateOption()) {
                CrossCricketBussiness.updateCricketCourtGroupMatchData(matchData);
            }
        }

        for (LinkedList<CricketCourtTopUserData> list : topRankListMap.values()) {
            for (CricketCourtTopUserData topUserData : list) {
                if (topUserData.isInsertOption()) {
                    CrossCricketBussiness.addCricketCourtTopUserData(topUserData);
                } else if (topUserData.isUpdateOption()) {
                    CrossCricketBussiness.updateCricketCourtTopUserData(topUserData);
                }
            }
        }

        List<DbCricketHotBattleLog> dbCricketHotBattleLogs = new ArrayList<>(cricketDbData.getDbCricketHotBattleLogList());
        for (DbCricketHotBattleLog dbCricketHotBattleLog : dbCricketHotBattleLogs) {
            CricketCrossBusiness.saveDbCricketHotBattleLog(dbCricketHotBattleLog);
        }

        for (CricketCourtLockGroup lockGroup : lockGroupMap.values()) {
            if (lockGroup.isInsertOption()) {
                CrossCricketBussiness.addCricketCourtLockGroup(lockGroup);
            } else if (lockGroup.isUpdateOption()) {
                CrossCricketBussiness.updateCricketCourtLockGroup(lockGroup);
            }
        }

        // 日志保存
        try {
            CrossCricketCourtLog.save();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }

    public static int battleLogLimit() {
        List<Integer> list = StringUtils.stringToIntegerList(GameConfig.CRICKET_FIGHT_REPORT_HOT_VALUE_LIMIT, "\\|");
        return list.get(2);
    }

    /**
     * 分数变更调用这个方法
     */
    public static void scoreChange(long serverId, long userId, long score) {
        // 判断下有没有竞技场信息
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return;
        }
        CricketCourtUserData userData = getCricketCourtUserData(serverId, userId);
        if (userData == null) {
            return;
        }
        if (!hasGroup(userData)) {
            // 加入新分组
            joinGroup(userData);
            getLogger().info("serverId:{},userId:{},no group, join group,cricketId:{},groupId:{}", serverId, userId, userData.getCourtId(), userData.getGroupId());
        }
        if (score == userData.getScore()) {
            return;
        }
        // 获取下分数变动前的数据
        long beforeScore = userData.getScore();
        int beforeRank = getUserRank(userData);
        userData.setScore(score);
        userData.setUpdateTime(System.currentTimeMillis());
        rankChange(userData);
        long afterScore = userData.getScore();
        int afterRank = getUserRank(userData);
        CrossCricketCourtLog.addLogCricketCourtChangeScore(new LogCricketCourtChangeScore(
                serverId,
                userId,
                userData.getRound(),
                userData.getCourtId(),
                userData.getGroupId(),
                beforeScore,
                afterScore,
                beforeRank,
                afterRank
        ));
    }

    /**
     * 用户是否有分组信息
     *
     * @param userData 用户数据
     */
    private static boolean hasGroup(CricketCourtUserData userData) {
        if (userData == null) {
            return false;
        }
        return userData.getGroupId() != -1;
    }


    /**
     * 获取竞技场用户数据，不存在则初始化一个
     */
    public static CricketCourtUserData getCricketCourtUserData(long serverId, long userId) {
        if (serverId <= 0 || userId <= 0) {
            return null;
        }
        if (!courtUserDataMap.containsKey(serverId)) {
            synchronized (courtUserDataMap) {
                if (!courtUserDataMap.containsKey(serverId)) {
                    courtUserDataMap.put(serverId, new ConcurrentHashMap<>());
                }
            }
        }
        Map<Long, CricketCourtUserData> map = courtUserDataMap.get(serverId);
        if (!map.containsKey(userId)) {
            synchronized (map) {
                if (!map.containsKey(userId)) {
                    // 初始赛场
                    CricketCourtConfig initCourtConfig = config.getInitCourtConfig();
                    if (initCourtConfig == null) {
                        return null;
                    }
                    CricketCourtUserData userData = new CricketCourtUserData();
                    userData.setServerId(serverId);
                    userData.setUserId(userId);
                    // 初始化赛场id
                    userData.setCourtId(initCourtConfig.getCourtId());
                    // -1 未分组状态
                    userData.setGroupId(-1);
                    // 初始化分数
                    userData.setScore(GameConfig.CRICKET_FIGHT_BEGIN_RANK_SCORE);
                    userData.setParam("");
                    userData.setLastCourtId(-1);
                    userData.setLastRank(-1);
                    userData.setRound(curRound.get());
                    userData.setUpdateTime(System.currentTimeMillis());
                    userData.setDefenseDataList(new ArrayList<>());
                    userData.setCourtBadgeId(0);
                    userData.setInsertOption();
                    map.put(userId, userData);
                }
            }
        }
        return map.get(userId);
    }

    /**
     * 分组榜单变更
     */
    public static void rankChange(CricketCourtUserData userData) {
        if (curRound.get() == 0 || userData == null || userData.getCourtId() == -1 || userData.getGroupId() == -1) {
            return;
        }
        CricketCourtRankListModel rankListModel = getRankListModel(curRound.get(), userData.getCourtId(), userData.getGroupId());
        rankListModel.rankChange(userData);
    }

    public static int getTopRankUser(long serverId, long userId) {
        if (inRoundChange) {
            return GameErrorCode.E_CRICKET_COURT_IN_ROUND_CHANGE;
        }
        // 判断下有没有竞技场信息
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        if (topRankListMap == null || topRankListMap.size() == 0) {
            return GameErrorCode.E_CRICKET_COURT_TOP_USER_NOT_FOUND;
        }
        // 获取下我的服务器的宗师场的匹配分组
        CricketCourtGroupMatchData groupMatchData = getMatchGroupId(config.getMaxCourtConfig().getCourtId(), serverId, false);
        if (groupMatchData == null) {
            return GameErrorCode.E_CRICKET_COURT_TOP_USER_NOT_FOUND;
        }
        // 匹配分组id
        int matchGroupId = groupMatchData.getMatchGroupId();
        LinkedList<CricketCourtTopUserData> topUserDatalist = topRankListMap.get(matchGroupId);
        if (topUserDatalist == null || topUserDatalist.size() == 0) {
            return GameErrorCode.E_CRICKET_COURT_TOP_USER_NOT_FOUND;
        }
        CricketProto.CricketCourtGetTopUserRespMsg.Builder respMsg = CricketProto.CricketCourtGetTopUserRespMsg.newBuilder();
        respMsg.setRet(0);
        int myRank = -1;
        long myScore = 0;
        int rank = 0;
        for (CricketCourtTopUserData topUserData : topUserDatalist) {
            // 获取下这个用户的信息
            CricketCourtUserData courtUserData = getCricketCourtUserData(topUserData.getServerId(), topUserData.getUserId());
            if (courtUserData == null) {
                continue;
            }
            com.yanqu.road.entity.player.UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(topUserData.getUserId());
            if (userBaseInfo == null) {
                continue;
            }
            rank++;
            CricketProto.CricketCourtRankTempMsg.Builder temp = CricketProto.CricketCourtRankTempMsg.newBuilder();
            temp.setUserId(topUserData.getUserId());
            temp.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
            temp.setValue(topUserData.getScore());
            temp.setParam(topUserData.getParam());
            temp.setRank(rank);
            temp.setCourtBadgeId(courtUserData.getCourtBadgeId());
            respMsg.addRankList(temp);
            if (topUserData.getServerId() == serverId && topUserData.getUserId() == userId) {
                myRank = rank;
                myScore = topUserData.getScore();
            }
        }
        respMsg.setMyRank(myRank);
        respMsg.setMyScore(myScore);
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.U_CRICKET_COURT_GET_TOP_USER_DATA, respMsg));
        return 0;
    }

    /**
     * 宗师榜膜拜
     */
    public static int topRankUserWorship(long serverId, long userId) {
        if (!systemOpen(serverId)) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        // 获取下我的服务器的宗师场的匹配分组
        CricketCourtGroupMatchData groupMatchData = getMatchGroupId(config.getMaxCourtConfig().getCourtId(), serverId, false);
        if (groupMatchData == null) {
            return GameErrorCode.E_CRICKET_COURT_TOP_USER_NOT_FOUND;
        }
        // 匹配分组id
        int matchGroupId = groupMatchData.getMatchGroupId();
        LinkedList<CricketCourtTopUserData> topUserDatalist = topRankListMap.get(matchGroupId);
        if (topUserDatalist == null || topUserDatalist.size() == 0) {
            return GameErrorCode.E_CRICKET_COURT_TOP_USER_NOT_FOUND;
        }
        // 获取宗师榜前三名
        List<CricketCourtTopUserData> courtTopUserDataList = new ArrayList<>();
        for (CricketCourtTopUserData courtTopUserData : topUserDatalist) {
            if (courtTopUserDataList.size() >= 3) {
                break;
            }
            courtTopUserDataList.add(courtTopUserData);
        }
        // 随机一个人
        CricketCourtTopUserData courtTopUserData = courtTopUserDataList.get(randomHelper.next(0, courtTopUserDataList.size()));
        CricketProto.CrossCricketTopRankWorshipRespMsg.Builder builder = CricketProto.CrossCricketTopRankWorshipRespMsg.newBuilder();
        builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(CrossUserMgr.getUserBaseInfo(courtTopUserData.getUserId())));
        // 回游戏服
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.S_CRICKET_TOP_RANK_WORSHIP_FROM_CROSS, builder));
        return 0;
    }

    public static CricketCourtRankListModel getRankListModel(int round, int courtId, int groupId) {
        if (!rankListModelMap.containsKey(round)) {
            rankListModelMap.put(round, new ConcurrentHashMap<>());
        }
        if (!rankListModelMap.get(round).containsKey(courtId)) {
            rankListModelMap.get(round).put(courtId, new ConcurrentHashMap<>());
        }
        if (!rankListModelMap.get(round).get(courtId).containsKey(groupId)) {
            CricketCourtRankListModel model = new CricketCourtRankListModel(groupId, getMaxRank(), new CricketCourtRankListSort());
            List<CricketCourtUserData> rankList = new ArrayList<>();
            for (Map<Long, CricketCourtUserData> userMap : courtUserDataMap.values()) {
                for (CricketCourtUserData data : userMap.values()) {
                    // 防守阵容数量满足才加进来
                    if (data.getDefenseDataList().size() < GameConfig.CRICKET_FIGHT_PLAYER_LIMIT) {
                        continue;
                    }
                    if (data.getRound() == round && data.getCourtId() == courtId && data.getGroupId() == groupId) {
                        rankList.add(data);
                    }
                }
            }
            model.setRankList(rankList);
            rankListModelMap.get(round).get(courtId).put(groupId, model);
        }
        return rankListModelMap.get(round).get(courtId).get(groupId);
    }

    public static CricketCourtData getCricketCourtData(int round) {
        return courtDataMap.get(round);
    }

    /**
     * 发奖励
     */
    public static void sendRankReward() {
        // 获取当前轮次的
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        // 判断下当前轮次是否已发奖
        if (courtData == null || courtData.isRankReward()) {
            return;
        }
        // 是否到了结算期
        if (System.currentTimeMillis() < courtData.getRewardTime()) {
            return;
        }
        synchronized (lock) {
            if (courtData.isRankReward()) {
                return;
            }
            if (!rankListModelMap.containsKey(curRound.get())) {
                return;
            }
            // 做个容错,内存维护一个发奖的用户防止重复发奖
            List<Long> allUserIdList = new ArrayList<>();
            // 发奖励
            // 聚合一下  区服, List<user>
            Map<Long, List<CricketCourtRankRewardHelper>> map = new ConcurrentHashMap<>();
            Map<Integer, Map<Integer, CricketCourtRankListModel>> courtMap = rankListModelMap.get(curRound.get());
            for (Map<Integer, CricketCourtRankListModel> groupMap : courtMap.values()) {
                for (Map.Entry<Integer, CricketCourtRankListModel> entry : groupMap.entrySet()) {
                    Integer groupId = entry.getKey();
                    if (groupId == -1) {
                        continue;
                    }
                    int rank = 0;
                    for (CricketCourtUserData courtUserData : entry.getValue().getRankList()) {
                        rank++;

                        if (allUserIdList.contains(courtUserData.getUserId()) || courtUserData.getGroupId() == -1) {
//                            getLogger().error("serverId:{},userId:{}, groupId :{},cricket court rank reward error!!!", courtUserData.getServerId(), courtUserData.getUserId(), courtUserData.getGroupId());
                            continue;
                        }
                        allUserIdList.add(courtUserData.getUserId());

                        CricketCourtRankRewardHelper helper = new CricketCourtRankRewardHelper();
                        helper.setServerId(courtUserData.getServerId());
                        helper.setUserId(courtUserData.getUserId());
                        helper.setRank(rank);
                        helper.setCourtId(courtUserData.getCourtId());
                        List<CricketCourtRankRewardHelper> list = map.getOrDefault(courtUserData.getServerId(), new ArrayList<>());
                        list.add(helper);
                        map.put(courtUserData.getServerId(), list);
                    }
                }
            }
            // 发到区服处理
            for (Map.Entry<Long, List<CricketCourtRankRewardHelper>> entry : map.entrySet()) {
                CricketProto.CrossSendCricketCourtRankRewardMsg.Builder builder = CricketProto.CrossSendCricketCourtRankRewardMsg.newBuilder();
                Long serverId = entry.getKey();
                List<CricketCourtRankRewardHelper> list = entry.getValue();
                for (CricketCourtRankRewardHelper rewardHelper : list) {
                    CricketProto.CricketCourtRankUserTempMsg.Builder temp = CricketProto.CricketCourtRankUserTempMsg.newBuilder();
                    temp.setServerId(rewardHelper.getServerId());
                    temp.setUserId(rewardHelper.getUserId());
                    temp.setCourtId(rewardHelper.getCourtId());
                    temp.setRank(rewardHelper.getRank());
                    builder.addUser(temp);
                }
                MessageHelper.sendPacket(serverId, 0, YanQuMessageUtils.buildMessage(Protocol.S_CRICKET_SEND_RANK_REWARD_FROM_CROSS, builder));
            }

            // 发完奖励记录下所有用户的排名信息
            for (Map<Long, CricketCourtUserData> dataMap : courtUserDataMap.values()) {
                for (CricketCourtUserData userData : dataMap.values()) {
                    int userRank = -1;
                    int changeType = 0;
                    if (userData.getCourtId() != -1 && userData.getGroupId() != -1) {
                        CricketCourtRankListModel rankListModel = getRankListModel(userData.getRound(), userData.getCourtId(), userData.getGroupId());
                        int groupNum = 0;
                        if (rankListModel != null) {
                            userRank = rankListModel.getRank(userData);
                            groupNum = rankListModel.getRankList().size();
                        }
                        // 当前场次晋级人数
                        int upCnt = config.getUpCnt(userData.getCourtId(), groupNum);
                        // 当前场次保留人数
                        int keepCnt = config.getKeepCnt(userData.getCourtId(), groupNum);
                        if (userRank <= upCnt) {
                            // 晋级
                            changeType = 2;
                        } else if (userRank <= upCnt + keepCnt) {
                            // 不变
                            changeType = 1;
                        }
                    }
                    CrossCricketCourtLog.addLogCricketCourtRoundRank(new LogCricketCourtRoundRank(
                            userData.getRound(),
                            userData.getServerId(),
                            userData.getUserId(),
                            userData.getCourtId(),
                            userData.getGroupId(),
                            userData.getScore(),
                            userData.getParam(),
                            userRank,
                            changeType
                    ));
                }
            }
            courtData.setRankReward(true);
        }
    }

    public static int getUserRank(CricketCourtUserData userData) {
        if (userData.getCourtId() == -1 || userData.getGroupId() == -1) {
            return -1;
        }
        CricketCourtRankListModel rankListModel = getRankListModel(userData.getRound(), userData.getCourtId(), userData.getGroupId());
        return rankListModel.getRank(userData);
    }


    /**
     * 生成分组
     */
    public static void generateGroup() {
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        // 判断下当前轮次是否已分组
        if (courtData == null || courtData.isGenerateGroup()) {
            return;
        }
        synchronized (lock) {
            if (courtData.isGenerateGroup()) {
                return;
            }
            maxMatchGroupId = new AtomicInteger(0);
            // 开始分组
            // 有哪些赛场
            Set<Integer> courtIdSet = new HashSet<>();
            // 默认有第一赛场
            courtIdSet.add(config.getInitCourtConfig().getCourtId());
            for (Map<Long, CricketCourtUserData> userDataMap : courtUserDataMap.values()) {
                for (CricketCourtUserData courtUserData : userDataMap.values()) {
                    if (courtUserData.getCourtId() != -1) {
                        courtIdSet.add(courtUserData.getCourtId());
                    }
                }
            }
            for (int courtId : courtIdSet) {
                // 生成赛场的分组匹配信息
                generateMatchGroup(courtId);
            }
            courtData.setGenerateGroup(true);
        }
    }

    /**
     * 匹配分组
     *
     * @param courtId 赛场id
     */
    private static void generateMatchGroup(int courtId) {
        // 学徒场是特殊处理的,直接读运营给的区服范围
        if (courtId == config.getInitCourtConfig().getCourtId()) {
            for (CricketCourtLockGroup lockGroup : lockGroupMap.values()) {
                CricketCourtGroupMatchData groupMatchData = new CricketCourtGroupMatchData();
                groupMatchData.setRound(curRound.get());
                groupMatchData.setCourtId(courtId);
                // 学徒场只有一个分组范围,最小量级
                List<Integer> serverGroupIdList = new ArrayList<>();
                serverGroupIdList.add(lockGroup.getGroupId());
                groupMatchData.setServerGroupIdList(serverGroupIdList);
                // 更新赛场分组上限
                groupMatchData.setGroupLimit(getCourtGroupLimit(courtId, groupMatchData));
                groupMatchData.setMatchGroupId(maxMatchGroupId.incrementAndGet());
                // 开服天数
                long openDay = getAverageServerOpenDay(lockGroup);
                // 开服天数区间索引
                groupMatchData.setServerOpenDayIndex(getServerOpenDayRangeIndex(courtId, openDay));
                groupMatchData.setUpdateTime(System.currentTimeMillis());
                groupMatchData.setInsertOption();
                groupMatchDataMap.put(groupMatchData.getMatchGroupId(), groupMatchData);
                // 扩充分组时初始化分组，生成分组
                initCourtGroup(courtId, groupMatchData);
            }
        } else {
            // 其他的按规则分组
            // 初始生成下空分组
            initMatchGroup(courtId, lockGroupMap.values());
            // 开始分配
            for (CricketCourtLockGroup lockGroup : lockGroupMap.values()) {
                putMatchGroup(courtId, lockGroup);
            }
        }
    }

    /**
     * 初始空的匹配分组
     *
     * @param courtId    赛场id
     * @param lockGroups 锁定分组列表
     */
    private static void initMatchGroup(int courtId, Collection<CricketCourtLockGroup> lockGroups) {
        long nowTime = System.currentTimeMillis();
        CricketCourtConfig courtConfig = config.getCricketCourtConfig(courtId);
        if (courtConfig == null) {
            // 没有配置
            return;
        }
        Map<Integer, List<CricketCourtLockGroup>> openMap = new ConcurrentHashMap<>();
        for (CricketCourtLockGroup lockGroup : lockGroups) {
            // 开服天数
            long openDay = getAverageServerOpenDay(lockGroup);
            // 开服天数区间索引
            int dayRangeIndex = getServerOpenDayRangeIndex(courtId, openDay);
            List<CricketCourtLockGroup> list = openMap.getOrDefault(dayRangeIndex, new ArrayList<>());
            list.add(lockGroup);
            openMap.put(dayRangeIndex, list);
        }
        // 分一下组
        Map<Integer, Integer> groupCntMap = new HashMap<>();
        for (Map.Entry<Integer, List<CricketCourtLockGroup>> entry : openMap.entrySet()) {
            Integer openDayIndex = entry.getKey();
            // 计算下多少个分组
            // 区服数量
            int serverCnt = 0;
            for (CricketCourtLockGroup lockGroup : entry.getValue()) {
                if (lockGroup == null) {
                    continue;
                }
                // 按实际生效的区服数量来算
                for (Long serverId : lockGroup.getServerList()) {
                    long tempOpenDay = ServerListMgr.getServerOpenDay(serverId);
                    // 判断是否满足蛐蛐开启天数的条件
                    if (tempOpenDay >= GameConfig.CRICKET_OPEN_DAY) {
                        serverCnt++;
                    }

                }
            }
            // 计算出有多少个匹配分组,做个容错，和分组取个最小值，防止大于匹配分组出现空分组
            groupCntMap.put(openDayIndex, (int) Math.min(entry.getValue().size(), Math.ceil(serverCnt * 1.0 / courtConfig.getFightRangeServer())));
        }

        // 初始化一下分组
        for (Map.Entry<Integer, Integer> entry : groupCntMap.entrySet()) {
            for (int i = 0; i < entry.getValue(); i++) {
                CricketCourtGroupMatchData groupMatchData = new CricketCourtGroupMatchData();
                groupMatchData.setRound(curRound.get());
                groupMatchData.setCourtId(courtId);
                // 这里空的就行
                groupMatchData.setServerGroupIdList(new ArrayList<>());
                // 更新赛场分组上限
                groupMatchData.setGroupLimit(getCourtGroupLimit(courtId, groupMatchData));
                groupMatchData.setMatchGroupId(maxMatchGroupId.incrementAndGet());
                // 开服天数区间索引
                groupMatchData.setServerOpenDayIndex(entry.getKey());
                groupMatchData.setUpdateTime(System.currentTimeMillis());
                groupMatchData.setInsertOption();
                groupMatchDataMap.put(groupMatchData.getMatchGroupId(), groupMatchData);
            }
        }

    }

    /**
     * 获取开服天数区间索引
     */
    public static int getServerOpenDayRangeIndex(int courtId, long openDay) {
        CricketCourtConfig courtConfig = config.getCricketCourtConfig(courtId);
        if (courtConfig == null) {
            return -1;
        }
        List<Integer> rangeList = StringUtils.stringToIntegerList(courtConfig.getFightRangeDay(), "\\|");
        int index = -1;
        for (int i = 0; i < rangeList.size(); i++) {
            if (openDay >= rangeList.get(i)) {
                index = i;
            }
        }
        return index;
    }

    /**
     * 加入匹配分组
     *
     * @param courtId 赛场id
     */
    private static CricketCourtGroupMatchData putMatchGroup(int courtId, CricketCourtLockGroup lockGroup) {
        CricketCourtConfig courtConfig = config.getCricketCourtConfig(courtId);
        // 开服天数
        long openDay = getAverageServerOpenDay(lockGroup);
        // 开服天数区间索引
        int dayRangeIndex = getServerOpenDayRangeIndex(courtId, openDay);

        // 目标分组区服数量
        int size = lockGroup.getServerList().size();

        long nowTime = System.currentTimeMillis();

        List<CricketCourtGroupMatchData> matchDataList = new ArrayList<>();
        // 找出没满的区服分组范围
        int minServerCnt = Integer.MAX_VALUE;
        for (CricketCourtGroupMatchData groupMatchData : groupMatchDataMap.values()) {
            // 开服天数区间相同的
            if (courtId != groupMatchData.getCourtId() || groupMatchData.getServerOpenDayIndex() != dayRangeIndex) {
                continue;
            }
            // 区服数量
            int serverCnt = 0;
            for (Integer groupId : groupMatchData.getServerGroupIdList()) {
                CricketCourtLockGroup tempLockGroup = lockGroupMap.get(groupId);
                if (tempLockGroup == null) {
                    continue;
                }
                // 按实际生效的区服数量来算
                for (Long serverId : tempLockGroup.getServerList()) {
                    long tempOpenDay = ServerListMgr.getServerOpenDay(serverId);
                    // 判断是否满足蛐蛐开启天数的条件
                    if (tempOpenDay >= GameConfig.CRICKET_OPEN_DAY) {
                        serverCnt++;
                    }
                }
            }
            // 满足条件的，且
            if (serverCnt + size > courtConfig.getFightRangeServer()) {
                continue;
            }
            // 找下下最小的区服分组
            if (serverCnt <= minServerCnt) {
                if (serverCnt < minServerCnt) {
                    minServerCnt = serverCnt;
                    matchDataList = new ArrayList<>();
                }
                // 找下下最小的区服分组
                matchDataList.add(groupMatchData);
            }
        }
        // 随机一个分组出来
        CricketCourtGroupMatchData groupMatchData = null;
        if (!matchDataList.isEmpty()) {
            groupMatchData = matchDataList.get(randomHelper.next(0, matchDataList.size()));
            if (!groupMatchData.getServerGroupIdList().contains(lockGroup.getGroupId())) {
                groupMatchData.getServerGroupIdList().add(lockGroup.getGroupId());
                // 更新赛场分组上限
                groupMatchData.setGroupLimit(getCourtGroupLimit(courtId, groupMatchData));
                groupMatchData.setUpdateTime(nowTime);
                groupMatchData.setUpdateOption();
            }
        } else {
            // 新增一个匹配分组
            groupMatchData = new CricketCourtGroupMatchData();
            groupMatchData.setRound(curRound.get());
            groupMatchData.setCourtId(courtId);
            // 学徒场只有一个分组范围,最小量级
            List<Integer> serverGroupIdList = new ArrayList<>();
            serverGroupIdList.add(lockGroup.getGroupId());
            groupMatchData.setServerGroupIdList(serverGroupIdList);
            groupMatchData.setMatchGroupId(maxMatchGroupId.incrementAndGet());
            // 更新赛场分组上限
            groupMatchData.setGroupLimit(getCourtGroupLimit(courtId, groupMatchData));
            groupMatchData.setServerOpenDayIndex(dayRangeIndex);
            groupMatchData.setUpdateTime(nowTime);
            groupMatchData.setInsertOption();
            groupMatchDataMap.put(groupMatchData.getMatchGroupId(), groupMatchData);
        }
        // 扩充分组时初始化分组，生成分组
        initCourtGroup(courtId, groupMatchData);
        return groupMatchData;
    }

    /**
     * 初始化分組
     */
    private static void initCourtGroup(int courtId, CricketCourtGroupMatchData groupMatchData) {
        // 计算需要添加多少个赛场分组
        int groupCnt = getGroupCnt(courtId, groupMatchData.getMatchGroupId());
        int groupLimit = groupMatchData.getGroupLimit();
        while (groupCnt < groupLimit) {
            addGroup(courtId, groupMatchData.getMatchGroupId());
            groupCnt++;
        }
    }


    /**
     * 更新赛场分组上限
     */
    public static int getCourtGroupLimit(int courtId, CricketCourtGroupMatchData groupMatchData) {
        // 低级场特殊处理 都是1组
        if (courtId == config.getInitCourtConfig().getCourtId()) {
            return 1;
        }
        List<Long> allServerIdList = new ArrayList<>();
        for (Integer groupId : groupMatchData.getServerGroupIdList()) {
            CricketCourtLockGroup lockGroup = lockGroupMap.get(groupId);
            if (lockGroup != null) {
                allServerIdList.addAll(lockGroup.getServerList());
            }
        }
        // 获取当前赛场的人数
        int userCnt = 0;
        for (Map<Long, CricketCourtUserData> userDataMap : courtUserDataMap.values()) {
            for (CricketCourtUserData userData : userDataMap.values()) {
                if (userData.getDefenseDataList().size() < GameConfig.CRICKET_FIGHT_DEF_FIT_NUM) {
                    continue;
                }
                if (userData.getCourtId() == courtId && allServerIdList.contains(userData.getServerId())) {
                    userCnt++;
                }
            }
        }
        CricketCourtConfig courtConfig = config.getCricketCourtConfig(courtId);
        if (courtConfig == null) {
            return 0;
        }
        int groupLimit = userCnt / courtConfig.getNum();
        if (userCnt % courtConfig.getNum() >= courtConfig.getModLimit()) {
            groupLimit = groupLimit + 1;
        }
        // 做个容错,有人至少有一组
        if (userCnt > 0) {
            groupLimit = Math.max(1, groupLimit);
        }
        return courtConfig.getGroupLimit() == -1 ? groupLimit : Math.min(groupLimit, courtConfig.getGroupLimit());

    }


    /**
     * 获取分组内的平均开服天数
     */
    public static long getAverageServerOpenDay(CricketCourtLockGroup lockGroup) {
        long totalOpenDay = 0;
        for (Long serverId : lockGroup.getServerList()) {
            totalOpenDay += ServerListMgr.getServerOpenDay(serverId);
        }
        return totalOpenDay / lockGroup.getServerList().size();
    }

    /**
     * 加入分组
     */
    public static void joinGroup(CricketCourtUserData courtUserData) {
        // 当前竞技场信息
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return;
        }
        long nowTime = System.currentTimeMillis();
        if (nowTime > courtData.getRewardTime() || nowTime > courtData.getEndTime()) {
            return;
        }
        int courtId = courtUserData.getCourtId();
        // 没有赛场
        if (courtId == -1) {
            getLogger().error("userId:{},join group error,no courId!!!", courtUserData.getUserId());
            return;
        }
        if (courtUserData.getGroupId() != -1) {
            // 有分组不处理
            getLogger().error("userId:{},join group error,already has groupId!!!", courtUserData.getUserId());
            return;
        }
        List<CricketCourtDefenseData> defenseDataList = courtUserData.getDefenseDataList();
        if (defenseDataList == null || defenseDataList.size() < GameConfig.CRICKET_FIGHT_PLAYER_LIMIT) {
            return;
        }
        CricketCourtGroupData groupData = null;
        synchronized (lock) {
            // 获取下匹配分组
            CricketCourtGroupMatchData groupMatchData = getMatchGroupId(courtId, courtUserData.getServerId(), true);
            if (groupMatchData == null) {
                // 这里为空 就说明是新服且不在锁定分组里的了
                // 先查下分组
                CricketServerGroup cricketServerGroup = CricketServerGroupMgr.getServerGroupByServerId(courtUserData.getServerId());
                if (cricketServerGroup != null) {
                    // 有分组
                    CricketCourtLockGroup newLockGroup = lockGroupMap.get(cricketServerGroup.getGroupId());
                    if (newLockGroup != null) {
                        // 这里是新服
                        newLockGroup.getServerList().add(courtUserData.getServerId());
                        newLockGroup.setUpdateOption();
                        getLogger().info("userId:{},join group,add new lock group!!!", courtUserData.getUserId());
                    } else {
                        // 这里是新分组
                        if (cricketServerGroup.getOpenStatus() != 0) {
                            getLogger().info("add new lock group!!! , groupId:{}", cricketServerGroup.getGroupId());
                            CricketCourtLockGroup lockGroup = new CricketCourtLockGroup();
                            lockGroup.setRound(curRound.get());
                            lockGroup.setGroupId(cricketServerGroup.getGroupId());
                            lockGroup.setServerList(new HashSet<>(cricketServerGroup.getServerList()));
                            lockGroup.setLockTime(System.currentTimeMillis());
                            lockGroup.setInsertOption();
                            lockGroupMap.put(lockGroup.getGroupId(), lockGroup);

                            putMatchGroup(courtId, lockGroup);
                        }
                    }
                }

//                CricketCourtLockGroup lockGroup = getLockGroupByServerId(courtUserData.getServerId());
//                if (lockGroup != null) {
//                    // 加一个新的匹配分组
//                    groupMatchData = putMatchGroup(courtId, lockGroup);
//                }
                groupMatchData = getMatchGroupId(courtId, courtUserData.getServerId(), true);
            }
            // 新分组还没加到匹配分组中
            if (groupMatchData == null) {
                // 操作一下数据
                CricketServerGroup cricketServerGroup = CricketServerGroupMgr.getServerGroupByServerId(courtUserData.getServerId());
                if (cricketServerGroup == null) {
                    getLogger().error("userId:{},cricketServerGroup is null!!!", courtUserData.getUserId());
                }
                if (cricketServerGroup != null) {
                    getLogger().error("新分组加入到匹配分组,赛场id:{}，分组id:{}", courtId, cricketServerGroup.getGroupId());
                    // 有分组
                    CricketCourtLockGroup lockGroup = lockGroupMap.get(cricketServerGroup.getGroupId());
                    // 生成新分组
                    putMatchGroup(courtId, lockGroup);
                }
                groupMatchData = getMatchGroupId(courtId, courtUserData.getServerId(), true);
            }
            groupData = getGroupData(courtId, getRandomGroupId(courtUserData, false));
            // 第一次取不到说明没有空的分组，都是塞满了，第二次取无视分组人数上限
            if (groupData == null) {
                if (courtId == config.getInitCourtConfig().getCourtId()) {
                    // 学徒场满人则加分组
                    if (groupMatchData != null) {
                        groupData = addGroup(courtId, groupMatchData.getMatchGroupId());
                    }
                } else {
                    groupData = getGroupData(courtId, getRandomGroupId(courtUserData, true));
                }
            }
            if (groupData == null) {
                // 还是取不到就别进了，有异常了
                getLogger().error("userId:{},join group error,no group!!!", courtUserData.getUserId());
                return;
            }
            groupData.setNum(groupData.getNum() + 1);
            groupData.setUpdateTime(System.currentTimeMillis());
        }
        courtUserData.setGroupId(groupData.getGroupId());
        courtUserData.setScore(GameConfig.CRICKET_FIGHT_BEGIN_RANK_SCORE);
        courtUserData.setUpdateTime(System.currentTimeMillis());
        // 更新下分组榜单
        rankChange(courtUserData);
    }

    /**
     * 获取当前区服的分组
     *
     * @param serverId 区服id
     */
    public static CricketCourtLockGroup getLockGroupByServerId(long serverId) {
        for (CricketCourtLockGroup lockGroup : lockGroupMap.values()) {
            if (lockGroup.getServerList().contains(serverId)) {
                return lockGroup;
            }
        }
        return null;
    }

    private static int getGroupCnt(int courtId, int matchGroupId) {
        if (!courtGroupDataMap.containsKey(courtId)) {
            return 0;
        }
        int groupCnt = 0;
        for (CricketCourtGroupData groupData : courtGroupDataMap.get(courtId).values()) {
            if (groupData.getMatchGroupId() != matchGroupId) {
                continue;
            }
            groupCnt++;
        }
        return groupCnt;
    }


    private static int getNoFullGroupCnt(int courtId, int matchGroupId) {
        if (!courtGroupDataMap.containsKey(courtId)) {
            return 0;
        }
        int groupCnt = 0;
        CricketCourtConfig courtConfig = config.getCricketCourtConfig(courtId);
        for (CricketCourtGroupData groupData : courtGroupDataMap.get(courtId).values()) {
            if (groupData.getMatchGroupId() != matchGroupId) {
                continue;
            }
            if (groupData.getNum() < courtConfig.getNum()) {
                groupCnt++;
            }
        }
        return groupCnt;
    }

    /**
     * 添加分组
     */
    public static CricketCourtGroupData addGroup(int courtId, int matchGroupId) {
        CricketCourtGroupData groupData = new CricketCourtGroupData();
        groupData.setCourtId(courtId);
        groupData.setGroupId(maxGroupId.incrementAndGet());
        groupData.setMatchGroupId(matchGroupId);
        groupData.setNum(0);
        groupData.setRound(curRound.get());
        groupData.setUpdateTime(System.currentTimeMillis());
        groupData.setInsertOption();
        int groupId = groupData.getGroupId();
        if (!courtGroupDataMap.containsKey(courtId)) {
            courtGroupDataMap.put(courtId, new ConcurrentHashMap<>());
        }
        if (!courtGroupDataMap.get(courtId).containsKey(groupId)) {
            courtGroupDataMap.get(courtId).put(groupId, groupData);
        }
        return groupData;
    }

    /**
     * 获取分组信息
     */
    public static CricketCourtGroupData getGroupData(int courtId, int groupId) {
        if (courtId == -1 || groupId == -1) {
            return null;
        }
        if (!courtGroupDataMap.containsKey(courtId)) {
            return null;
        }
        return courtGroupDataMap.get(courtId).get(groupId);

    }

    /**
     * 获取当前区服的匹配分组
     * @param isCurrent 是否本轮，  true 本轮， false 上一轮
     */
    public static CricketCourtGroupMatchData getMatchGroupId(int courtId, long serverId, boolean isCurrent) {
        Map<Integer, CricketCourtGroupMatchData> map = isCurrent ? groupMatchDataMap : lastGroupMatchDataMap;
        for (CricketCourtGroupMatchData matchData : map.values()) {
            if (matchData.getCourtId() != courtId) {
                continue;
            }
            // 这边也做个容错，有清掉上一轮这边就不会进来
            if (isCurrent) {
                if (matchData.getRound() != curRound.get()) {
                    continue;
                }
            } else {
                if (matchData.getRound() != curRound.get() - 1) {
                    continue;
                }
            }
            for (Integer groupId : matchData.getServerGroupIdList()) {
                // 从锁定分组里拿
                CricketCourtLockGroup lockGroup = lockGroupMap.get(groupId);
                if (lockGroup == null) {
                    continue;
                }
                if (lockGroup.getServerList().contains(serverId)) {
                    return matchData;
                }
            }
        }
        return null;
    }

    /**
     * 获取随机一个分组
     *
     * @param ignoreLimit 是否忽略上限
     */
    public static int getRandomGroupId(CricketCourtUserData courtUserData, boolean ignoreLimit) {
        int courtId = courtUserData.getCourtId();
        if (!courtGroupDataMap.containsKey(courtId)) {
            return -1;
        }
        // 获取我的匹配分组
        CricketCourtGroupMatchData groupMatchData = getMatchGroupId(courtId, courtUserData.getServerId(), true);
        if (groupMatchData == null) {
            return -1;
        }
        List<Integer> groupIdList = new ArrayList<>();
        Map<Integer, CricketCourtGroupData> dataMap = courtGroupDataMap.getOrDefault(courtId, new ConcurrentHashMap<>());
        int minNum = Integer.MAX_VALUE;
        if (ignoreLimit) {
            // 无视分组人数上限， 往人数最少的分组塞人
            for (CricketCourtGroupData groupData : dataMap.values()) {
                if (groupData.getMatchGroupId() != groupMatchData.getMatchGroupId()) {
                    continue;
                }
                if (groupData.getNum() <= minNum) {
                    if (groupData.getNum() < minNum) {
                        minNum = groupData.getNum();
                        // 清空下列表
                        groupIdList = new ArrayList<>();
                    }
                    groupIdList.add(groupData.getGroupId());
                }
            }
        } else {
            List<CourtGroupNumHelper> groupNumHelpers = new ArrayList<>();
            for (CricketCourtGroupData groupData : dataMap.values()) {
                if (groupData.getMatchGroupId() != groupMatchData.getMatchGroupId()) {
                    continue;
                }
                groupNumHelpers.add(new CourtGroupNumHelper(groupData.getGroupId(), groupData.getNum()));
            }
            // 排个序,人数从大到小排序
            groupNumHelpers.sort(Comparator.comparing(CourtGroupNumHelper::getNum).reversed());
            int totalRangeSize = groupNumHelpers.size() % GameConfig.CRICKET_FIGHT_EXPANSION_GROUP == 0 ? groupNumHelpers.size() / GameConfig.CRICKET_FIGHT_EXPANSION_GROUP : groupNumHelpers.size() / GameConfig.CRICKET_FIGHT_EXPANSION_GROUP + 1;
            CricketCourtConfig courtConfig = config.getCricketCourtConfig(courtId);
            for (int i = 0; i < totalRangeSize; i++) {
                if (groupIdList.size() > 0) {
                    // 找到了退出
                    break;
                }
                // 第i个区间  [i * GameConfig.CRICKET_FIGHT_EXPANSION_GROUP , (i+1) * GameConfig.CRICKET_FIGHT_EXPANSION_GROUP)
                for (int j = i * GameConfig.CRICKET_FIGHT_EXPANSION_GROUP; j < (i + 1) * GameConfig.CRICKET_FIGHT_EXPANSION_GROUP; j++) {
                    int index = Math.min(j, groupNumHelpers.size() - 1);
                    CourtGroupNumHelper helper = groupNumHelpers.get(index);
                    if (helper.getNum() >= courtConfig.getNum()) {
                        continue;
                    }
                    if (helper.getNum() <= minNum) {
                        if (helper.getNum() < minNum) {
                            minNum = helper.getNum();
                            // 清空下列表
                            groupIdList = new ArrayList<>();
                        }
                        groupIdList.add(helper.getGroupId());
                    }
                }
            }
        }
        if (groupIdList.size() == 0) {
            return -1;
        }
        return groupIdList.get(randomHelper.next(0, groupIdList.size()));
    }

    /**
     * 轮次切换
     *
     * @param userData 用户数据
     */
    public static void changeRound(CricketCourtUserData userData) {
        if (userData.getRound() == curRound.get()) {
            return;
        }
        // 记录一下切换轮次前的数据
        userData.setLastCourtId(userData.getCourtId());
        // 上一轮的排名
        int myLastRank = -1;
        int groupNum = 0;
        // 判断下我有没有在分组内,不在分组直接降级
        if (userData.getGroupId() == -1) {
            CricketCourtConfig preOpenCourtConfig = config.getPreOpenCourtConfig(userData.getCourtId());
            if (preOpenCourtConfig != null) {
                userData.setCourtId(preOpenCourtConfig.getCourtId());
            }
        } else {
            // 获取上一轮的赛场排名数据
            CricketCourtRankListModel rankListModel = getRankListModel(userData.getRound(), userData.getCourtId(), userData.getGroupId());
            // 分组人数
            groupNum = rankListModel.getRankList().size();
            myLastRank = rankListModel.getRank(userData);
            // 晋级  rank => [1,upNum] 且有下一个赛场
            CricketCourtConfig nextOpenCourtConfig = config.getNextOpenCourtConfig(userData.getCourtId());
            // 当前场次晋级人数
            int upCnt = config.getUpCnt(userData.getCourtId(), groupNum);
            // 当前场次保留人数
            int keepCnt = config.getKeepCnt(userData.getCourtId(), groupNum);
            if (myLastRank >= 1 && myLastRank <= upCnt) {
                if (nextOpenCourtConfig != null) {
                    userData.setCourtId(nextOpenCourtConfig.getCourtId());
                }
                // 保留人数，不需要处理
            } else if (keepCnt > 0 && myLastRank >= upCnt + 1 && myLastRank <= upCnt + keepCnt) {
                // 保留人数，不需要处理
            } else {
                // 剩下的全部淘汰
                CricketCourtConfig preOpenCourtConfig = config.getPreOpenCourtConfig(userData.getCourtId());
                if (preOpenCourtConfig != null) {
                    userData.setCourtId(preOpenCourtConfig.getCourtId());
                }
                // 保留人数，不需要处理
            }
        }
        userData.setLastRank(myLastRank);
        userData.setGroupId(-1);
        userData.setLastGroupNum(groupNum);
        userData.setScore(GameConfig.CRICKET_FIGHT_BEGIN_RANK_SCORE);
        userData.setParam("");
        userData.setRound(curRound.get());
        userData.setUpdateTime(System.currentTimeMillis());
    }


    /**
     * 获取竞技场信息
     *
     * @param serverId 区服id
     * @param userId   用户id
     */
    public static int getCourtInfo(long serverId, long userId, List<CricketProto.CricketMatchDataTemp> cricketDefenseList) {
        if (inRoundChange) {
            return GameErrorCode.E_CRICKET_COURT_IN_ROUND_CHANGE;
        }
        if (!systemOpen(serverId)) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        // 获取当前轮次竞技场信息
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        // 获取下个人信息,不存在则创建一个
        CricketCourtUserData userData = getCricketCourtUserData(serverId, userId);
        if (userData == null) {
            return GameErrorCode.E_CRICKET_COURT_DATA_NOT_FOUND;
        }
        // 更新下防守
        updateUserCricketDefense(serverId, userId, cricketDefenseList);
        // 判断下有没有分组，没有的话塞个分组
        if (!hasGroup(userData)) {
            // 过了结算期先不加入分组了
            long nowTime = System.currentTimeMillis();
            if (nowTime >= courtData.getEndTime() || nowTime >= courtData.getRewardTime()) {
                return GameErrorCode.E_CRICKET_COURT_IN_REWARD_TIME;
            }
            // 加入新分组
            joinGroup(userData);
        }
        CricketProto.CricketGetCourtInfoRespMsg.Builder respMsg = CricketProto.CricketGetCourtInfoRespMsg.newBuilder();
        // 获取下榜单
        int myRank = -1;
        if (userData.getCourtId() != -1 && userData.getGroupId() != -1) {
            CricketCourtRankListModel rankListModel = getRankListModel(curRound.get(), userData.getCourtId(), userData.getGroupId());
            int rank = 0;
            for (CricketCourtUserData courtUserData : new ArrayList<>(rankListModel.getRankList())) {
                rank++;
                CricketProto.CricketCourtRankTempMsg.Builder rankTemp = CricketProto.CricketCourtRankTempMsg.newBuilder();
                rankTemp.setUserId(courtUserData.getUserId());
                rankTemp.setValue(courtUserData.getScore());
                rankTemp.setParam(courtUserData.getParam());
                rankTemp.setRank(rank);
                rankTemp.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(CrossUserMgr.getUserBaseInfo(courtUserData.getUserId())));
                rankTemp.setCourtBadgeId(courtUserData.getCourtBadgeId());
                if (courtUserData.getServerId() == serverId && courtUserData.getUserId() == userId) {
                    myRank = rank;
                }
                respMsg.addRankList(rankTemp);
            }
        }
        respMsg.setRet(0);
        respMsg.setCourtId(userData.getCourtId());
        respMsg.setMyRank(myRank);
        respMsg.setValue(userData.getScore());
        respMsg.setParam(userData.getParam());
        respMsg.setLastCourtId(userData.getLastCourtId());
        respMsg.setLastRank(userData.getLastRank());
        respMsg.setLastGroupNum(userData.getLastGroupNum());
        respMsg.setRound(courtData.getRound());
        respMsg.setRewardTime(courtData.getRewardTime());
        respMsg.setEndTime(courtData.getEndTime());
        respMsg.setHaveTopRank(haveTopRank(serverId));
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.U_CRICKET_GET_COURT_INFO, respMsg));
        return 0;
    }

    public static boolean haveTopRank(long serverId) {
        boolean haveTopRank = false;
        CricketCourtGroupMatchData groupMatchData = getMatchGroupId(config.getMaxCourtConfig().getCourtId(), serverId, false);
        if (groupMatchData != null) {
            // 匹配分组id
            int matchGroupId = groupMatchData.getMatchGroupId();
            LinkedList<CricketCourtTopUserData> topUserDatalist = topRankListMap.get(matchGroupId);
            if (topUserDatalist != null && topUserDatalist.size() != 0) {
                haveTopRank = true;
            }
        }
        return haveTopRank;
    }

    /**
     * 轮次切换
     */
    public static void changeRound() {
        if (inRoundChange) {
            return;
        }
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return;
        }
        long nowTime = System.currentTimeMillis();
        if (nowTime < courtData.getEndTime()) {
            return;
        }
        synchronized (lock) {
            if (inRoundChange) {
                return;
            }
            if (nowTime < courtData.getEndTime()) {
                return;
            }
            inRoundChange = true;
            // 轮次切换
            // 开始切换轮次,判断下有没有发奖励了，没发奖励就先发一下
            if (!courtData.isRankReward()) {
                sendRankReward();
            }
            // 保存一份匹配分组数据到内存
            lastGroupMatchDataMap = new ConcurrentHashMap<>(groupMatchDataMap);

            // 切换轮次需要把分组清掉
            groupMatchDataMap.clear();

            // 生成下宗师榜名单
            generateTopRankListModel();

            // 生成新的竞技场轮次
            genNewRoundCourtData();
            // 清空下分组信息
            courtGroupDataMap.clear();
            // 分组编号也重新计数
            maxGroupId = new AtomicInteger(0);

            // 晋级、淘汰
            for (Map<Long, CricketCourtUserData> dataMap : courtUserDataMap.values()) {
                for (CricketCourtUserData userData : dataMap.values()) {
                    changeRound(userData);
                }
            }
            // 锁定当前的匹配分组
            lockMatchGroup();

            // 分组
            generateGroup();

            // 自动加入分组
//            long nextDayZeroTime = DateHelper.getTodayZeroTimeStamp() / 1000 + DateHelper.DAY_SECONDS;
//            for (Map<Long, CricketCourtUserData> dataMap : courtUserDataMap.values()) {
//                for (CricketCourtUserData userData : dataMap.values()) {
//                    UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userData.getUserId());
//                    if (userBaseInfo == null) {
//                        continue;
//                    }
//                    long days = (nextDayZeroTime - userBaseInfo.getLastLoginTime()) / DateHelper.DAY_SECONDS;
//                    if (days > 7) {//取7日活跃
//                        continue;
//                    }
//                    // 满足条件自动加入竞技场
//                    joinGroup(userData);
//                }
//            }

            inRoundChange = false;
        }
    }

    /**
     * 锁定分组列表
     */
    private static Map<Integer, CricketCourtLockGroup> lockGroupMap = new ConcurrentHashMap<>();

    public static Map<Integer, CricketCourtLockGroup> getLockGroupMap() {
        return lockGroupMap;
    }

    /**
     * 锁定当前的匹配分组
     */
    private static void lockMatchGroup() {
        synchronized (lock) {
            Map<Integer, CricketCourtLockGroup> tempLockGroupMap = new ConcurrentHashMap<>();
            // 所有的分组
            Map<Integer, CricketServerGroup> serverGroupMap = CricketServerGroupMgr.getServerGroupMap(channelId);
            for (CricketServerGroup serverGroup : serverGroupMap.values()) {
                if (serverGroup == null || serverGroup.getOpenStatus() == 0) {
                    continue;
                }
                CricketCourtLockGroup lockGroup = new CricketCourtLockGroup();
                lockGroup.setRound(curRound.get());
                lockGroup.setGroupId(serverGroup.getGroupId());
                lockGroup.setServerList(new HashSet<>(serverGroup.getServerList()));
                lockGroup.setLockTime(System.currentTimeMillis());
                lockGroup.setInsertOption();
                tempLockGroupMap.put(lockGroup.getGroupId(), lockGroup);
            }
            lockGroupMap = tempLockGroupMap;
        }
    }

    /**
     * 生成新一轮的竞技场信息
     */
    public static void genNewRoundCourtData() {
        CricketCourtData courtData = new CricketCourtData();
        // 超过了，重置轮次
        courtData.setRound(curRound.incrementAndGet());
        // 结算时间
        courtData.setRewardTime(DateHelper.getTodayZeroTimeStamp() + GameConfig.CRICKET_FIGHT_SETTLE_TIME * DateHelper.MINUTE_MILLIONS);
        // 结束时间
        courtData.setEndTime(DateHelper.getTodayZeroTimeStamp() + GameConfig.CRICKET_FIGHT_LOOP_DAY * DateHelper.DAY_MILLIONS);
        courtData.setGenerateGroup(false);
        courtData.setRankReward(false);
        courtData.setUpdateTime(System.currentTimeMillis());
        courtData.setInsertOption();
        courtDataMap.put(curRound.get(), courtData);
    }

    /**
     * 系统是否开放
     */
    public static boolean systemOpen(long serverId) {
        if (!channelSystemOpen()) {
            return false;
        }
        // 系统开放拿实时的
        Map<Integer, CricketServerGroup> serverGroupMap = CricketServerGroupMgr.getServerGroupMap(channelId);
        if (serverGroupMap == null) {
            return false;
        }
        // 是否包含分组
        boolean hasServerGroup = false;
        for (CricketServerGroup serverGroup : serverGroupMap.values()) {
            if (serverGroup.getOpenStatus() == 1 && serverGroup.getServerList().contains(serverId)) {
                hasServerGroup = true;
            }
        }
        return serverGroupMap.size() > 0 && hasServerGroup;
    }

    public static boolean channelSystemOpen() {
        // 系统开放拿实时的
        Map<Integer, CricketServerGroup> serverGroupMap = CricketServerGroupMgr.getServerGroupMap(channelId);
        if (serverGroupMap == null) {
            return false;
        }
        for (CricketServerGroup serverGroup : serverGroupMap.values()) {
            // 只要有一个分组是关闭的，就当没开
            if (serverGroup.getOpenStatus() == 0) {
                return false;
            }
        }
        return serverGroupMap.size() > 0;
    }


    /**
     * 生成宗师榜名单
     */
    public static void generateTopRankListModel() {
        synchronized (lock) {
            // 清空当前宗师榜
            topRankListMap = new ConcurrentHashMap<>();
            if (rankListModelMap == null || !rankListModelMap.containsKey(curRound.get())) {
                return;
            }
            Map<Integer, Map<Integer, CricketCourtRankListModel>> rankListMap = rankListModelMap.get(curRound.get());
            if (rankListMap == null) {
                return;
            }
            for (Map.Entry<Integer, Map<Integer, CricketCourtRankListModel>> entry : rankListMap.entrySet()) {
                int courtId = entry.getKey();
                if (courtId != config.getMaxCourtConfig().getCourtId()) {
                    continue;
                }
                Map<Integer, CricketCourtRankListModel> map = entry.getValue();
                if (map == null) {
                    continue;
                }
                for (Map.Entry<Integer, CricketCourtRankListModel> rankListModelEntry : map.entrySet()) {
                    int groupId = rankListModelEntry.getKey();
                    // 获取下匹配分组
                    CricketCourtGroupData groupData = getGroupData(courtId, groupId);
                    if (groupData == null) {
                        continue;
                    }
                    int matchGroupId = groupData.getMatchGroupId();
                    CricketCourtRankListModel rankListModel = rankListModelEntry.getValue();
                    if (rankListModel == null) {
                        continue;
                    }
                    LinkedList<CricketCourtTopUserData> topRankList = new LinkedList<>();
                    int rank = 0;
                    for (CricketCourtUserData courtUserData : rankListModel.getRankList()) {
                        rank++;
                        // 人数超过不记录
                        if (rank > GameConfig.CRICKET_FIGHT_MASTER_SHOW_NUM) {
                            break;
                        }
                        CricketCourtTopUserData topUserData = new CricketCourtTopUserData();
                        topUserData.setServerId(courtUserData.getServerId());
                        topUserData.setUserId(courtUserData.getUserId());
                        topUserData.setScore(courtUserData.getScore());
                        topUserData.setParam(courtUserData.getParam());
                        topUserData.setRound(courtUserData.getRound());
                        topUserData.setRank(rank);
                        topUserData.setMatchGroupId(matchGroupId);
                        topUserData.setInsertOption();
                        topRankList.add(topUserData);
                    }
                    topRankListMap.put(matchGroupId, topRankList);
                }
            }
        }
    }

    public static void crossCricketSyncData(long serverId, long userId) {
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return;
        }
        CricketCourtUserData userData = getCricketCourtUserData(serverId, userId);
        if (userData == null) {
            return;
        }
        // 同步下跨服竞技场信息
        CricketProto.CrossCricketSyncDataRespMsg.Builder respMsg = CricketProto.CrossCricketSyncDataRespMsg.newBuilder();
        respMsg.setSystemOpen(systemOpen(serverId));
        respMsg.setRound(courtData.getRound());
        respMsg.setRewardTime(courtData.getRewardTime());
        respMsg.setEndTime(courtData.getEndTime());
        respMsg.setHaveTopRank(haveTopRank(serverId));
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.S_CRICKET_SYNC_DATA_FROM_CROSS, respMsg));
    }


    public static int match(long serverId, long userId, boolean isRefresh) throws Exception {
        if (inRoundChange) {
            return GameErrorCode.E_CRICKET_COURT_IN_ROUND_CHANGE;
        }
        if (!systemOpen(serverId)) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        // 发了奖励不能再匹配
        if (courtData.isRankReward()) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        long nowTime = System.currentTimeMillis();
        // 到了结算期不能再匹配
        if (nowTime > courtData.getRewardTime() || nowTime > courtData.getEndTime()) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        CricketCourtUserData userData = getCricketCourtUserData(serverId, userId);
        if (userData == null) {
            return GameErrorCode.E_CRICKET_COURT_DATA_NOT_FOUND;
        }
        // 开始匹配
        List<CricketProto.CricketUserBattleMatchDataTemp> list = matchCricketDefense(userData);
        if (list.size() == 0) {
            return GameErrorCode.E_CRICKET_NO_USER_MATCH;
        }
        // 回到游戏服处理
        CricketProto.CrossCricketMatchRespMsg.Builder crossResp = CricketProto.CrossCricketMatchRespMsg.newBuilder();
        crossResp.setRet(0);
        crossResp.setIsRefresh(isRefresh);
        crossResp.addAllUserData(list);
        crossResp.setRound(courtData.getRound());
        crossResp.setCourtId(userData.getCourtId());
        crossResp.setGroupId(userData.getGroupId());
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.S_CRICKET_MATCH_FROM_CROSS, crossResp));
        return 0;
    }

    /**
     * 随机匹配
     *
     * @param userData
     */
    public static List<CricketProto.CricketUserBattleMatchDataTemp> matchCricketDefense(CricketCourtUserData userData) {
        List<CricketProto.CricketUserBattleMatchDataTemp> result = new ArrayList<>();
        // 随机三个人给他
        // 获取下分组
        CricketCourtRankListModel rankListModel = getRankListModel(curRound.get(), userData.getCourtId(), userData.getGroupId());
        int myRank = rankListModel.getRank(userData);
        int lastRank = rankListModel.getRankList().size();
        // 取高区间、中区间、低区间
        // 高区间
        int highRangeIndex;
        // 中区间
        int middleRangeIndex;
        // 低区间
        int lowRangeIndex;
        // 区间人数
        int ruleRange = GameConfig.CRICKET_FIGHT_MATCH_RULE;
        // 当前区间
        int myRange = myRank / ruleRange;
        // 总区间
        int totalRange = lastRank % ruleRange == 0 ? lastRank / ruleRange : lastRank / ruleRange + 1;
        if (myRange == 0) {
            // 头部区间
            highRangeIndex = myRange;
            middleRangeIndex = Math.min(totalRange, highRangeIndex + 1);
            lowRangeIndex = Math.min(totalRange, middleRangeIndex + 1);
        } else if (myRange == totalRange) {
            // 尾部区间
            lowRangeIndex = totalRange;
            middleRangeIndex = Math.max(0, lowRangeIndex - 1);
            highRangeIndex = Math.max(0, middleRangeIndex - 1);
        } else {
            // 我的区间为中区间
            middleRangeIndex = myRange;
            highRangeIndex = Math.max(0, middleRangeIndex - 1);
            lowRangeIndex = Math.min(totalRange, middleRangeIndex + 1);
        }
        List<CricketCourtUserData> matchUserList = new ArrayList<>();
        // 随机区间取人
        List<CricketCourtUserData> highRangeUserList = new ArrayList<>(rankListModel.getRangeUserList(highRangeIndex * ruleRange + 1, (highRangeIndex + 1) * ruleRange));
        List<CricketCourtUserData> middleRangeUserList = new ArrayList<>(rankListModel.getRangeUserList(middleRangeIndex * ruleRange + 1, (middleRangeIndex + 1) * ruleRange));
        List<CricketCourtUserData> lowRangeUserList = new ArrayList<>(rankListModel.getRangeUserList(lowRangeIndex * ruleRange + 1, (lowRangeIndex + 1) * ruleRange));

        // 区间各取一个人
        // 高区间
        CricketCourtUserData highUser = randomMatchUser(highRangeUserList, matchUserList, userData.getUserId());
        if (highUser != null) {
            matchUserList.add(highUser);
        }
        // 中区间
        CricketCourtUserData middleUser = randomMatchUser(middleRangeUserList, matchUserList, userData.getUserId());
        if (middleUser != null) {
            matchUserList.add(middleUser);
        } else {
            // 往高区间补
            middleUser = randomMatchUser(highRangeUserList, matchUserList, userData.getUserId());
            if (middleUser != null) {
                matchUserList.add(middleUser);
            }
        }
        // 低区间
        CricketCourtUserData lowUser = randomMatchUser(lowRangeUserList, matchUserList, userData.getUserId());
        if (lowUser != null) {
            matchUserList.add(lowUser);
        } else {
            // 先往中区间补
            lowUser = randomMatchUser(middleRangeUserList, matchUserList, userData.getUserId());
            if (lowUser != null) {
                matchUserList.add(lowUser);
            } else {
                // 往高区间补
                lowUser = randomMatchUser(highRangeUserList, matchUserList, userData.getUserId());
                if (lowUser != null) {
                    matchUserList.add(lowUser);
                }
            }
        }
        if (highUser != null) {
            CricketProto.CricketUserBattleMatchDataTemp dataTemp = parseCricketUser(highUser, 2);
            if (dataTemp != null) {
                result.add(dataTemp);
            }
        }
        if (middleUser != null) {
            CricketProto.CricketUserBattleMatchDataTemp dataTemp = parseCricketUser(middleUser, 1);
            if (dataTemp != null) {
                result.add(dataTemp);
            }
        }
        if (lowUser != null) {
            CricketProto.CricketUserBattleMatchDataTemp dataTemp = parseCricketUser(lowUser, 0);
            if (dataTemp != null) {
                result.add(dataTemp);
            }
        }
        return result;
    }

    private static CricketCourtUserData randomMatchUser(List<CricketCourtUserData> rangeUserList, List<CricketCourtUserData> hadMatchUserList, long myUserId) {
        List<CricketCourtUserData> list = new ArrayList<>();
        for (CricketCourtUserData userData : rangeUserList) {
            if (hadMatchUserList.stream().anyMatch(t -> t.getUserId() == userData.getUserId()) || myUserId == userData.getUserId()) {
                continue;
            }
            list.add(userData);
        }
        if (list.size() == 0) {
            return null;
        }
        return list.get(randomHelper.next(0, list.size()));
    }

    /**
     * 取用户信息
     *
     * @param range 0 低区间  1 中区间 2 高区间
     */
    public static CricketProto.CricketUserBattleMatchDataTemp parseCricketUser(CricketCourtUserData courtUserData, int range) {
        CricketProto.CricketUserBattleMatchDataTemp.Builder builder = CricketProto.CricketUserBattleMatchDataTemp.newBuilder();
        // 防守阵容
        List<CricketCourtDefenseData> defenseDataList = courtUserData.getDefenseDataList();
        if (defenseDataList == null || defenseDataList.size() < GameConfig.CRICKET_FIGHT_PLAYER_LIMIT) {
            return null;
        }
        builder.setUserInfo(CrossCricketPb.parseCricketUserBattleDataTemp(courtUserData));
        // 随机一个索引
        int randomIndex = randomHelper.next(0, 3);
        for (int i = randomIndex * 3; i < randomIndex * 3 + 3; i++) {
            CricketCourtDefenseData defenseData = defenseDataList.get(i);
            builder.addDefense(CrossCricketPb.parseCricketMatchDataTemp(defenseData));
        }
        builder.setWinScore(getFightAtkScore(range, true));
        builder.setFailScore(getFightAtkScore(range, false));
        builder.setDefenderWinScore(getFightDefScore(range, true));
        builder.setDefenderFailScore(getFightDefScore(range, false));
        return builder.build();
    }

    public static int getFightAtkScore(int range, boolean win) {
        List<String> paramList = StringUtils.stringToStringList(GameConfig.CRICKET_FIGHT_ATT_SCORE, "\\|");
        String param = paramList.get(range);
        String[] split = param.split(";");
        return Integer.parseInt(win ? split[0] : split[1]);
    }

    public static int getFightDefScore(int range, boolean win) {
        List<String> paramList = StringUtils.stringToStringList(GameConfig.CRICKET_FIGHT_DEF_SCORE, "\\|");
        String param = paramList.get(range);
        String[] split = param.split(";");
        return Integer.parseInt(win ? split[0] : split[1]);
    }


    public static void updateUserCricketDefense(long serverId, long userId, List<CricketProto.CricketMatchDataTemp> cricketDefenseList) {
        // 判断下有没有竞技场信息
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return;
        }
        CricketCourtUserData userData = getCricketCourtUserData(serverId, userId);
        if (userData == null) {
            return;
        }
        List<CricketCourtDefenseData> defenseDataList = new ArrayList<>();
        for (CricketProto.CricketMatchDataTemp cricketMatchDataTemp : cricketDefenseList) {
            defenseDataList.add(CrossCricketPb.parseCricketCourtDefenseData(cricketMatchDataTemp));
        }
        userData.setDefenseDataList(defenseDataList);
    }

    public static void updateUserCricketBadge(long serverId, long userId, int badgeId) {
        // 判断下有没有竞技场信息
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return;
        }
        CricketCourtUserData userData = getCricketCourtUserData(serverId, userId);
        if (userData == null) {
            return;
        }
        userData.setCourtBadgeId(badgeId);
    }

    /**
     * 获取当前有玩家的最高场次
     */
    private static int getCurMaxCourtId() {
        int courtId = -1;
        for (Integer id : courtGroupDataMap.keySet()) {
            courtId = Math.max(id, courtId);
        }
        return courtId;
    }


    public static void battleLogAdd(long serverId, long userId, CricketProto.CricketBattleLogAddReqMsg reqMsg) {
        // 判断下有没有竞技场信息
        CricketCourtData courtData = getCricketCourtData(curRound.get());
        if (courtData == null) {
            return;
        }
        // 当前竞技场最高场次
        int maxCricketCourtId = getCurMaxCourtId();
        CricketCourtUserData userData = getCricketCourtUserData(serverId, userId);
        if (userData == null || userData.getCourtId() != maxCricketCourtId) {
            return;
        }
        DbCricketHotBattleLog dbCricketHotBattleLog = DbCricketHotBattleLog.getInstance();
        List<CricketProto.CricketUserBattleDataTemp> userBattleDataList = reqMsg.getBattleLog().getMatchRound().getUserBattleDataList();
        if (userBattleDataList.size() != 2) {
            return;
        }
        List<Integer> list = StringUtils.stringToIntegerList(GameConfig.CRICKET_FIGHT_REPORT_HOT_VALUE_LIMIT, "\\|");
        // 是否满足前xxx名
        boolean flag = false;
        for (CricketProto.CricketUserBattleDataTemp dataTemp : userBattleDataList) {
            PlayerProto.PlayerBaseTempMsg playerBaseData = dataTemp.getPlayerBaseData();
            // 获取用户竞技场信息
            CricketCourtUserData courtUserData = getCricketCourtUserData(playerBaseData.getServerId(), dataTemp.getUserId());
            if (courtUserData == null) {
                continue;
            }
            // 判断下排名是否满足要求
            int userRank = getUserRank(courtUserData);
            if (userRank != -1 && userRank <= list.get(1)) {
                flag = true;
                break;
            }
        }
        if (!flag) {
            return;
        }
        dbCricketHotBattleLog.setUserId(userBattleDataList.get(0).getUserId());
        dbCricketHotBattleLog.setUserId1(userBattleDataList.get(1).getUserId());
        dbCricketHotBattleLog.setScore(reqMsg.getBattleLog().getMatchRound().getScore());
        for (CricketProto.CricketUserBattleDataTemp cricketUserBattleDataTemp : userBattleDataList) {
            CricketUserBaseInfo userBaseInfo = CricketUserBaseInfo.getInstance(cricketUserBattleDataTemp);
            dbCricketHotBattleLog.getUserBaseInfoList().add(userBaseInfo);
        }

        dbCricketHotBattleLog.setCricketBattleLog(reqMsg.getBattleLog());

        getCricketDbData().addDbCricketHotBattleLog(dbCricketHotBattleLog);
        dbCricketHotBattleLog.setNeedInsert(true);
        dbCricketHotBattleLog.refreshUpdateTime();
    }


    public static int battleLog(long serverId, long userId) {
        CricketProto.CricketBattleLogRespMsg.Builder respMsg = CricketProto.CricketBattleLogRespMsg.newBuilder();
        List<DbCricketHotBattleLog> dbCricketHotBattleLogList = getCricketDbData().getDbCricketHotBattleLogList();
        ArrayList<DbCricketHotBattleLog> dbCricketHotBattleLogs = new ArrayList<>(dbCricketHotBattleLogList);
        for (DbCricketHotBattleLog dbCricketHotBattleLog : dbCricketHotBattleLogs) {
            CricketProto.CricketBattleLogListTemp.Builder temp = CricketProto.CricketBattleLogListTemp.newBuilder();
            temp.setId(dbCricketHotBattleLog.getBattleLogId());
            for (CricketUserBaseInfo userBaseInfo : dbCricketHotBattleLog.getUserBaseInfoList()) {
                CricketProto.CricketUserBattleDataTemp cricketUserBattleDataTemp = userBaseInfo.toProtobuf();
                if (cricketUserBattleDataTemp != null) {
                    temp.addUser(cricketUserBattleDataTemp);
                }
            }
            temp.setTimestamp(dbCricketHotBattleLog.getCricketBattleLog().getTimestamp());
            temp.setScore(dbCricketHotBattleLog.getScore());
            temp.addAllAddRankScore(dbCricketHotBattleLog.getCricketBattleLog().getAddRankScoreList());
            temp.setType(dbCricketHotBattleLog.getBattleType());
            respMsg.addList(temp);
        }
        respMsg.setRet(0);
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.U_CRICKET_BATTLE_LOG, respMsg));
        return 0;
    }

    public static int battleLogDetail(long serverId, long userId, long id) {
        CricketProto.CricketBattleLogDetailRespMsg.Builder respMsg = CricketProto.CricketBattleLogDetailRespMsg.newBuilder();
        DbCricketHotBattleLog dbCricketHotBattleLog = null;

        List<DbCricketHotBattleLog> dbCricketHotBattleLogList = getCricketDbData().getDbCricketHotBattleLogList();

        List<DbCricketHotBattleLog> dbCricketHotBattleLogs = new ArrayList<>(dbCricketHotBattleLogList);
        for (DbCricketHotBattleLog cricketHotBattleLog : dbCricketHotBattleLogs) {
            if (cricketHotBattleLog.getBattleLogId() == id) {
                dbCricketHotBattleLog = cricketHotBattleLog;
            }
        }
        if (dbCricketHotBattleLog == null) {
            return GameErrorCode.E_CRICKET_BATTLE_LOG_DETAIL_NOT_FOUND;
        }
        respMsg.setMatchRound(dbCricketHotBattleLog.getCricketBattleLog());
        respMsg.setRet(0);
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.U_CRICKET_BATTLE_LOG_DETAIL, respMsg));
        return 0;
    }


    public static CricketDbData getCricketDbData() {
        return cricketDbData;
    }

    /**
     * 调试用
     */
    public static void debug() {
//        getLogger().info("---------------------------cricket court debug---------------------------");
//        scoreChange(88800001, 888000010000002L, 564);
//        scoreChange(88800001, 888000010000003L, 44);
//        scoreChange(88800001, 888000010000004L, 4488);
//        getRankListModel(1, 1, 1);
    }


}
